supce's blog

CSS Secret 读书笔记之折角效果&连字符断行


折角效果

有时候会把一个元素的右上角进行折叠,使元素显得更加有立体感。
要实现这种效果通常可以在右上角增加两个三角形:一个三角形来体现折页的形状,另一个三角形遮住元素的一角,用来模拟翻折所产生的缺口。但是这两种方式有以下两个缺陷:

  • 当折角元素之下的背景不是纯色而是一幅图案、一层纹理、一张照片或者渐变等,上面这种方式就不能完美实现了。
  • 当折角不是45°时也不能够完美实现。

这时候可以用下面这种方式解决

45°的折角

估计已经猜到,这时候要轮到到“万能”的渐变(linear-gradient)登场了。
基本思路是这样的:

  • 首先利用渐变在右上角创建一个透明的三角
  • 其次再利用渐变生成一个深色透明的三角产生折页效果

代码是这个样子的:

<div class="triangle-a">this is a test</div>
div{
    width: 10em;
    height: 6em;
    background: #fb3;
    font: 100%/6em sans-serif;
    text-align: center;
    color: white;
}
.triangle-a{
    background: #58a  /*回退样式*/
    background: linear-gradient(to left bottom,transparent 50%,rgba(0,0,0,.4) 0) no-repeat 100% 0 / 2em 2em,
                linear-gradient(-135deg,transparent 1.5em,#fb3 0);
}

注意:透明的切角是沿着渐变轴进行度量的,而background-size中的长度是正常的宽度和高度。所以在45°角的情况下,深色透明正方形的边长应为渐变轴的长度根号2倍。

其他度数的折角

如果需要产生一个30°的切角,这时候把渐变设置为-150deg,然后利用正余弦算出深色透明矩形的长和宽。

.triangle-b{
        background: linear-gradient(to left bottom,transparent 50%,rgba(0,0,0,.4) 0) no-repeat 100% 0 /3em 1.73em,
                    linear-gradient(-150deg,transparent 1.5em,#fb3 0);
    }

结果发现效果跟现实里是不一样的。

仔细观察会发现深色三角在形状和大小上与切下来的角是一样的。只是这个深色三角需要进行旋转才能模拟现实的效果。
为了方便对深色透明三角进行操作且不影响切口效果,这时候得利用伪元素来实现深色三角了!

.triangle-c{
    position: relative;
    background: linear-gradient(-150deg,transparent 1.5em,#58a 0);
    border-radius: .5em;
}
.triangle-c::before{
    content: "";
    position: absolute;
    top: 0;right: 0;
    background: linear-gradient(to left bottom,transparent 50%,rgba(0,0,0,.2) 0,rgba(0,0,0,.4)) no-repeat 100% 0;
    width: 3em;
    height: 1.73em;
}

这是只不过是把上面的效果用伪元素实现了一遍。
然后把伪元素的宽和高进行互换:width: 1.73em;height: 3em;

再观察下,把元素以右下角为中心进行旋转-30度,就可以使得深色透明三角与切口平行:

.triangle-c::before{
    content: "";
    position: absolute;
    top: 0;right: 0;
    background: linear-gradient(to left bottom,transparent 50%,rgba(0,0,0,.2) 0,rgba(0,0,0,.4)) no-repeat 100% 0;
    width: 1.73em;
    height: 3em;
    transform: rotate(-30deg);
    transform-origin: bottom right;
    border-bottom-left-radius: inherit;
    box-shadow: -.2em .2em .3em -.1em rgba(0,0,0,.15);
}

最后再把深色透明三角向上垂直移动就行,垂直移动量应为x-y如下图:

即修改代码如下:

transform: translateY(-1.3em) rotate(-30deg);

最终效果如下:

每换一个角度就需要重新计算,这时候可以用下预处理器:

@mixin folded-corner($background, $size, $angle: 30deg) {
    position: relative;
    background: $background; /* 回退 */
    background: linear-gradient($angle - 180deg, transparent $size, $background 0);
                border-radius: .5em;
                $x: $size / sin($angle);
                $y: $size / cos($angle);
    &::before {
        content: '';
        position: absolute;
        top: 0; right: 0;
        background: linear-gradient(to left bottom,transparent 50%, rgba(0,0,0,.2) 0,
        rgba(0,0,0,.4)) 100% 0 no-repeat;
        width: $y; height: $x;
        transform: translateY($y - $x)
        rotate(2*$angle - 90deg);
        transform-origin: bottom right;
        border-bottom-left-radius: inherit;
        box-shadow: -.2em .2em .3em -.1em rgba(0,0,0,.2);
    }
}

此时只需一行代码即可:

.triangle{ @include folded-corner(#58a,2em,40deg); }

连字符断行

这部分在英文文本中可能会遇到,处于强迫症,也把它写一下吧
文本如果在元素中能够两端对齐是很美观的。但是利用text-align:justify;会自动调整单词的间距,出现类似于“孤岛”的单词
比如:

div{
    width: 15em;
    margin: 20px auto;
    padding: 20px;
    font: 125%/1.5 sans-serif;
    background: #fb3;
}
.test-a{
    text-align: justify;
}
<div class="test-a">
This is a test.Like many things in computer science, word wrapping sounds simple and straightforward
</div>

虽然上图中文本两端对齐了,但是更加不美观了。
如果在两端对齐中使用连词符断行,使单词能够在音节分界处断开并折行,效果就会好一些。
这时候可以利用CSS3中的新属性hyphens,它接收三个值:none,manual,auto
manual是它的初始值,表示我们可以在任何时候手工插入连词符(&shy)以实现折行。
none表示禁用这种行为。
auto表示自动为我们添加连词符
比如上面的例子添加后:

可惜这个属性在chrome 53.0.2785.116 m中不兼容